﻿using Shared.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Shared.Method
{
    public class YcdMacBaseClass
    {
        //此类主要用于统一分配MAC地址
        private static Queue<string> _queueMacEpon = null;
        private static Queue<string> _queueMacStia = null;

        private static readonly object EPON_LOCK = new object();
        private static readonly object STIA_LOCAK = new object();

        private static readonly string BASE_PATH = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "MacCache\\";
        private static readonly string EPON_CACHE_NAME = "EPONCache";
        private static readonly string STIA_CACHE_NAME = "STIACache";

        public static void Initialize()
        {
            //初始化分配400个MAC地址，EPON和GPON各400个

            _queueMacEpon = new Queue<string>();
            _queueMacStia = new Queue<string>();

            ReadCache(SharedData.EPON);
            ReadCache(SharedData.STIA);

            if (_queueMacEpon.Count < 200)
                GetYcdMac(SharedData.EPON, 400);
            
            if (_queueMacStia.Count < 200)
                GetYcdMac(SharedData.STIA, 400);

            //        for (int i = 0; _queueMacEpon.Count < 200 && i < 3; i++)//分配EPON的MAC
            //{
            //    if (GetYcdMac(SharedData.EPON, 400)) break;
            //    System.Threading.Thread.Sleep(3000);
            //}

            //for (int j = 0; _queueMacStia.Count < 200 && j < 3; j++)//分配GPON的MAC
            //{
            //    if (GetYcdMac(SharedData.STIA, 400)) break;
            //    System.Threading.Thread.Sleep(3000);
            //}
        }
        /// <summary>
        /// 分配SN号码
        /// </summary>
        /// <param name="ponType"></param>
        /// <returns></returns>
        public static string DistMac(string ponType)
        {
            try
            {
                string ycdMac = null;

                if (ponType == SharedData.EPON)
                {
                    lock (EPON_LOCK)
                        ycdMac = _queueMacEpon.Dequeue();//放在分配MAC之前，减少冲突的可能性

                    if (_queueMacEpon.Count == 200 || _queueMacEpon.Count == 100 || _queueMacEpon.Count == 50 || _queueMacEpon.Count == 25)
                    {
                        //阶梯获取MAC，预防不同的进程之间冲突，异步获取YCDMAC，减少等待时间
                        Task.Factory.StartNew(()=>
                        {
                            GetYcdMac(ponType, 400);
                        });
                    }
                }
                else if (ponType == SharedData.STIA)
                {
                    lock (STIA_LOCAK)
                        ycdMac = _queueMacStia.Dequeue();

                    if (_queueMacStia.Count == 200 || _queueMacStia.Count == 100 || _queueMacStia.Count == 50 || _queueMacStia.Count == 25)
                    {
                        //阶梯获取MAC，预防不同的进程之间冲突
                        Task.Factory.StartNew(() =>
                        {
                            GetYcdMac(ponType, 400);
                        });
                    }
                }

                return ycdMac;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLogTxt("DistMac", "不能获取内部MAC", ex.ToString());
                return null;
            }
        }

        /// <summary>
        /// 获取400个内部MAC
        /// </summary>
        /// <returns></returns>
        private static bool GetYcdMac(string ponType, int macNum)
        {
            try
            {
                if (_queueMacEpon == null || _queueMacStia == null) return false;

                if (ponType != SharedData.EPON && ponType != SharedData.STIA) return false;

                //判断是否能够分配YCD MAC号码
                int ret = DBAccess.ExecuteNonQuery<YCD_DEVICE>(@"if exists(select * from YCD_DEVICE where ID=6000000000 and LIGHT_MODULE_SN is null)  update YCD_DEVICE set LIGHT_MODULE_SN = 888888888888 where ID = 6000000000");
                if (ret != 1) return false;

                long firstMacX = 0;//第一个MAC地址的16进制数

                List<Device_Data> listDevice = new List<Device_Data>();

                //查到最大ID的ponTYPE类型的PRODUCT YCD_MAC和DEVICE_DATA_ID
                YCD_DEVICE ycdW = new YCD_DEVICE();
                ycdW.SetWhere(string.Format("ID = (select top 1 ID from YCD_DEVICE where PON_TYPE='{0}' order by ID desc)", ponType));
                var selectYcd = DBAccess.SelectData(ycdW);
                //MessageBox.Show(selectProduct.message);

                string sqlDeviceWhere = null;//查询DEVICE的语句

                if (selectYcd == null || selectYcd.Count == 0)
                {
                    if (ponType == SharedData.EPON)
                    {
                        firstMacX = SharedData.FIRST_EPON_MAC;
                    }
                    else
                    {
                        firstMacX = SharedData.FIRST_GPON_MAC;
                    }
                    //找开头的device数据
                    sqlDeviceWhere = string.Format("ID IN (SELECT TOP {0} ID FROM Device_Data WHERE PONType='{1}')", macNum, ponType);
                }
                else
                {
                    firstMacX = Convert.ToInt64(selectYcd[0].YCD_MAC, 16) + 1;
                    //找大于ID的devicedata数据
                    sqlDeviceWhere = string.Format("ID IN (SELECT TOP {0} ID FROM Device_Data WHERE PONType='{1}'  AND ID>{2})", macNum, ponType, selectYcd[0].DEVICE_DATA_ID);
                }

                //查找对应的Device_ID

                Device_Data deviceW = new Device_Data();
                deviceW.SetWhere(sqlDeviceWhere);

                var selectDevice = DBAccess.SelectData(deviceW);

                if (selectDevice != null && selectDevice.Count > 0)//给listDevice赋值
                {
                    listDevice = selectDevice;
                }

                if (listDevice == null)
                {
                    //找开头的device数据
                    sqlDeviceWhere = string.Format("ID IN (SELECT TOP {0} ID FROM Device_Data WHERE PONType='{1}')", macNum, ponType);

                    deviceW.SetWhere(sqlDeviceWhere);

                    selectDevice = DBAccess.SelectData(deviceW);
                    listDevice = selectDevice;
                }
                else if (listDevice.Count < macNum)
                {
                    //找开头的device数据
                    sqlDeviceWhere = string.Format("ID IN (SELECT TOP {0} ID FROM Device_Data WHERE PONType='{1}')", macNum - listDevice.Count, ponType);
                    deviceW.SetWhere(sqlDeviceWhere);

                    selectDevice = DBAccess.SelectData(deviceW);
                    listDevice.AddRange(selectDevice);
                }

                if (listDevice == null || listDevice.Count != macNum)
                {
                    LogHelper.WriteErrLogTxt("GetYcdMac", "未能获得足够的DEVICE_DATA数据", "出错");
                    return false;
                }

                YCD_DEVICE ycdDevice = new YCD_DEVICE();


                for (int i = 0; i < listDevice.Count; i++)
                {
                    ycdDevice.Clear();
                    ycdDevice.SetUpdate();

                    ycdDevice.YCD_MAC = (firstMacX + i).ToString("X");
                    ycdDevice.DEVICE_DATA_ID = listDevice[i].ID;
                    ycdDevice.PON_TYPE = ponType;

                    var insertPro = DBAccess.InsertData(ycdDevice);

                    if (insertPro == 1)
                    {
                        if (ponType == SharedData.EPON)
                            lock (EPON_LOCK)
                                _queueMacEpon.Enqueue(ycdDevice.YCD_MAC);
                        else
                            lock (STIA_LOCAK)
                                _queueMacStia.Enqueue(ycdDevice.YCD_MAC);
                    }
                }

                if (DBAccess.ExecuteNonQuery<YCD_DEVICE>(@"update YCD_DEVICE set LIGHT_MODULE_SN=null where ID=6000000000") != 1)
                {
                    DBAccess.ExecuteNonQuery<YCD_DEVICE>(@"update YCD_DEVICE set LIGHT_MODULE_SN=null where ID=6000000000");
                }

                WriteCache(ponType);
                return true;

            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLogTxt("GetYcdMac()", "分配MAC错误", ex.ToString());
                return false;
            }
        }


        private static void WriteCache(string ponType)
        {
            //写缓存
            try
            {
                if (Directory.Exists(BASE_PATH) == false)
                {
                    Directory.CreateDirectory(BASE_PATH);
                }

                if (ponType == SharedData.EPON)
                {

                    StringBuilder strYcdMacEpon = new StringBuilder();
                    string[] macEpon = null;

                    lock (EPON_LOCK)//锁定
                        macEpon = _queueMacEpon.ToArray();

                    for (int i = 0; macEpon.Length > 0 && i < macEpon.Length; i++)
                    {
                        strYcdMacEpon.AppendLine(macEpon[i]);
                    }

                    string fileName = BASE_PATH + EPON_CACHE_NAME;
                    StreamWriter write = new StreamWriter(fileName);

                    write.Write(strYcdMacEpon.ToString());
                    write.Close();

                }
                else
                {
                    StringBuilder strYcdMacStia = new StringBuilder();
                    string[] macStia = null;

                    lock(STIA_LOCAK)
                        macStia= _queueMacStia.ToArray();

                    for (int i = 0; macStia.Length > 0 && i < macStia.Length; i++)
                    {
                        strYcdMacStia.AppendLine(macStia[i]);
                    }

                    string fileName = BASE_PATH + STIA_CACHE_NAME;
                    StreamWriter write = new StreamWriter(fileName);

                    write.Write(strYcdMacStia.ToString());

                    write.Close();

                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLogTxt("WriteCache", "写YCDMAC错误", ex.ToString());
            }
        }

        private static void ReadCache(string ponType)
        {
            //获取MAC地址，判断是否已经分配了，没有分配写入_queue中
            try
            {
                if (File.Exists(BASE_PATH + EPON_CACHE_NAME) == false || File.Exists(BASE_PATH + STIA_CACHE_NAME) == false)
                {
                    LogHelper.WriteDebugLogTxt("ReadCache", "未能找到缓存文件");
                    return;
                }

                //LogHelper.WriteDebugLogTxt("读取缓存", "读取ponType的缓存");

                string cache = null;
                string filePath = null;

                if (ponType == SharedData.EPON)
                {
                    filePath = BASE_PATH + EPON_CACHE_NAME;
                }
                else
                {
                    filePath = BASE_PATH + STIA_CACHE_NAME;
                }

                StreamReader ponRead = new StreamReader(filePath);

                cache = ponRead.ReadToEnd();
                ponRead.Close();

                //查询数据库，看有哪些MAC已经使用了，如果已经使用了，则从cache中删除掉
                if (string.IsNullOrEmpty(cache) == false && cache.Length > 140)//有10个以上的MAC地址
                {
                    string ponMac = "'" + cache.TrimEnd().Replace("\r\n", "','") + "'";

                    string sql = string.Format("select * from YCD_DEVICE where YCD_MAC in ({0}) and YCD_MAC not in(select YCD_MAC from TRCTL.dbo.PRODUCT where YCD_MAC in({0}))", ponMac);

                    var listYcdDevice = DBAccess.ExecuteGetTable<YCD_DEVICE>(sql);

                    for (int i = 0; listYcdDevice != null && listYcdDevice.Count > 0 && i < listYcdDevice.Count; i++)
                    {
                        if (ponType == SharedData.EPON)
                            lock (EPON_LOCK)
                                _queueMacEpon.Enqueue(listYcdDevice[i].YCD_MAC);
                        else
                            lock (STIA_LOCAK)
                                _queueMacStia.Enqueue(listYcdDevice[i].YCD_MAC);
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrLogTxt("ReadCache", "读取MAC缓存错误", ex.ToString());
            }
        }

    }
}
